﻿using JshRCSWebApi.Infrastructure.Domain.DTO.SysVehicle;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace JshRCSWebApi.Util.VehicleTool
{
    public class SeerTcpClient
    {
        TcpClient Client;
        public SeerTcpClient(string hostname, int port)
        {
            Client = new TcpClient(hostname, Convert.ToInt32(port));
        }
        public bool Connected => Client?.Connected ?? false;
        //public void Close() => Client.Close();
        //public void GetStream() => Client.GetStream();
        public string SendseerMessage(int number, string askJson)
        {
            string str = "";
            if (Client.Connected)
            {
                string hexCode = number.ToString("X").PadLeft(4, '0');
                NetworkStream serverStream = Client.GetStream();
                var newmsg = new SeerMessage();
                newmsg.head = bytesToStructure<SeerMessageHead>(hexStrTobyte(hexCode));
                newmsg.data = normalStrToHexByte(askJson);

                serverStream.Write(seerMessageHeadToBytes(newmsg.head), 0, Marshal.SizeOf(newmsg.head));
                serverStream.Write(newmsg.data, 0, newmsg.data.Length);
                serverStream.Flush();

                byte[] inStream = new byte[16];
                serverStream.Read(inStream, 0, 16);
                var recv_head = bytesToStructure<SeerMessageHead>(inStream);
                byte[] recvbyte = BitConverter.GetBytes(recv_head.length);
                Array.Reverse(recvbyte);
                var dsize = BitConverter.ToUInt32(recvbyte, 0);
                const int bufferSize = 512;
                List<byte> datalist = new List<byte>();
                int count = 0;

                while (true)
                {
                    byte[] buffer = new byte[bufferSize];
                    //Thread.Sleep(10);
                    int readSize = serverStream.Read(buffer, 0, bufferSize);

                    count += readSize;
                    datalist.AddRange(buffer);

                    if (count == dsize)
                    {
                        str = System.Text.Encoding.UTF8.GetString(datalist.ToArray());
                        str = str.Replace("\0", "");
                        //JObject jsonObject = JObject.Parse(str);
                        Client.Close();
                        break;
                    }
                    Thread.Sleep(10);
                }
                return str;
            }
            else
            {
                return str = "机器人网络连接断开，请检查网络";
            }
        }

        public string RobotPushMessage(string vehicleIP, int vehiclePort)
        {
            string str = ""; 
            if (Client.Connected)
            {
                NetworkStream networkStream = Client.GetStream();
                byte[] inStream = new byte[16];
                while (16 != networkStream.Read(inStream, 0, 16))
                {
                    Thread.Sleep(20);
                }
                var recv_head = bytesToStructure<SeerMessageHead>(inStream);

                byte[] recvbyte = BitConverter.GetBytes(recv_head.length);

                Array.Reverse(recvbyte);

                var dsize = BitConverter.ToUInt32(recvbyte, 0);


                const int bufferSize = 512;
                List<byte> datalist = new List<byte>();
                int count = 0;

                while (true)
                {
                    byte[] buffer = new byte[bufferSize];
                    int readSize = networkStream.Read(buffer, 0, bufferSize);

                    count += readSize;
                    datalist.AddRange(buffer);

                    if (count == dsize)
                    {
                        break;
                    }
                }
                str = System.Text.Encoding.UTF8.GetString(datalist.ToArray());
                Client.Close();
                return str;
            }
            else
            {
                return str = "机器人网络连接断开，请检查网络";
            }
            
        }
        public string SendseerMessage(RequestDTO requestDTO)
        {
            string str = "";
            if (Client.Connected)
            {
                string hexCode = requestDTO.number.ToString("X").PadLeft(4, '0');
                var headmessage = GetHeadChanges(hexCode, requestDTO.askJson);
                NetworkStream serverStream = Client.GetStream();
                var newmsg = new SeerMessage();
                newmsg.head = bytesToStructure<SeerMessageHead>(ReqhexStrTobyte(headmessage));
                newmsg.data = normalStrToHexByte(requestDTO.askJson);

                serverStream.Write(seerMessageHeadToBytes(newmsg.head), 0, Marshal.SizeOf(newmsg.head));
                serverStream.Write(newmsg.data, 0, newmsg.data.Length);
                serverStream.Flush();

                byte[] inStream = new byte[16];
                serverStream.Read(inStream, 0, 16);
                var recv_head = bytesToStructure<SeerMessageHead>(inStream);
                byte[] recvbyte = BitConverter.GetBytes(recv_head.length);
                Array.Reverse(recvbyte);
                var dsize = BitConverter.ToUInt32(recvbyte, 0);
                const int bufferSize = 512;
                List<byte> datalist = new List<byte>();
                int count = 0;

                while (true)
                {
                    byte[] buffer = new byte[bufferSize]; 
                    int readSize = serverStream.Read(buffer, 0, bufferSize);

                    count += readSize;
                    datalist.AddRange(buffer);

                    if (count == dsize)
                    {
                        str = System.Text.Encoding.UTF8.GetString(datalist.ToArray());
                        str = str.Replace("\0", ""); 
                        Client.Close();
                        break;
                    } 
                }
                return str;
            }
            else
            {
                return str = "机器人网络连接断开，请检查网络";
            }
        }
         

        public byte[] hexStrTobyte(string rpstr)
        {
            string hexString = "5A 01 00 01 00 00 00 00 05 15 00 00 00 00 00 00";
            hexString = hexString.Replace(" ", "");

            StringBuilder stringBuilder = new StringBuilder(hexString);
            stringBuilder.Replace(hexString.Substring(16, 20 - 16), rpstr, 16, 20 - 16);
            string newhexString = stringBuilder.ToString();


            if ((newhexString.Length % 2) != 0)
                newhexString += " ";
            byte[] returnBytes = new byte[newhexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(newhexString.Substring(i * 2, 2).Trim(), 16);
            return returnBytes;
        }
        public string GetHeadChanges(string headstring, string datastring)
        {
            string hexString = "5A 01 00 01 00 00 00 00 05 15 00 00 00 00 00 00";
            hexString = hexString.Replace(" ", "");

            StringBuilder stringBuilder = new StringBuilder(hexString);
            stringBuilder.Replace(hexString.Substring(16, 20 - 16), headstring, 16, 20 - 16);
            string newhexString = stringBuilder.ToString();

            var dsize = datastring.Trim().Length;

            var head = bytesToStructure<SeerMessageHead>(ReqhexStrTobyte(newhexString.Trim()));

            byte[] vv = ReqhexStrTobyte(dsize.ToString("X8"));

            head.length = BitConverter.ToUInt32(vv, 0);
            return BitConverter.ToString(seerMessageHeadToBytes(head)).Replace("-", " ");
        }

        public byte[] ReqhexStrTobyte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
            return returnBytes;
        }

        public byte[] normalStrToHexByte(string str)
        {
            byte[] result = new byte[str.Length];

            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
            for (int i = 0; i < buffer.Length; i++)
            {
                result[i] = Convert.ToByte(buffer[i].ToString("X2"), 16);
            }
            return result;
        }


        public byte[] seerMessageHeadToBytes(SeerMessageHead msg)
        {
            var hsize = Marshal.SizeOf(msg);
            byte[] bytes = new byte[hsize];
            IntPtr structPtr = Marshal.AllocHGlobal(hsize);
            Marshal.StructureToPtr(msg, structPtr, false);
            Marshal.Copy(structPtr, bytes, 0, hsize);
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }
        public T bytesToStructure<T>(byte[] bytesBuffer)
        {
            if (bytesBuffer.Length < Marshal.SizeOf(typeof(T)))
            {
                throw new ArgumentException("size error");
            }

            IntPtr bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length);
            for (int index = 0; index < bytesBuffer.Length; index++)
            {
                Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]);
            }
            T structObject = (T)Marshal.PtrToStructure(bufferHandler, typeof(T));
            Marshal.FreeHGlobal(bufferHandler);
            return structObject;

        }
    }
    /// <summary>
    /// TCP协议头部数据结构
    /// </summary>
    public struct SeerMessageHead
    {
        public byte sync;
        public byte version;
        public UInt16 number;
        public UInt32 length;
        public UInt16 type;
        private byte ref0;      //保留
        private byte ref1;      //保留
        private byte ref2;      //保留
        private byte ref3;      //保留
        private byte ref4;      //保留
        private byte ref5;      //保留

    };
    /// <summary>
    /// TCP协议发送数据结构（包含头部和data两部分）
    /// </summary>
    public struct SeerMessage
    {
        public SeerMessageHead head;
        public byte[] data;
        public int length()
        {
            return data.Length + Marshal.SizeOf(head);
        }
    }
}
